1

两种架构

现在使用React的开发模式主要有两种——freeMarker+React以及纯静态React页面开发。本文着重介绍纯静态React页面的开发方式。

freeMarker+React

由于以前是用YUI+freeMarker进行开发,为了保证以前的页面都能够正常访问,当重构老页面时会使用这种开发方式。
在这种开发模式下由java利用freeMarker生成并Render为html,通过browserify将js打包至资源目录并在browser中加载,React将app render至div中。

React纯静态页面

利用browserify使用同构的方式进行开发,直接产出html以及js文件放置到资源文件中通过文件路径访问页面。采用这种方式开发有以下优点:

  • PreRender产出的静态资源文件加载速度快
  • 前后端只通过ajax进行交互,使得前后端分离,各自约定好接口之后就能进行开发。
  • 同构的开发模式使得功能模块可以复用,比如模板、node的一些常用模块等等。

需要注意代码能同时在browser与node环境下执行,否则会出问题。当使用bom对象时,在componentDidMount生命周期中运行,此时node环境下已经完成了first render。

构建方式

在node环境下通过React.renderToString方法生成html,通过这种方式生成的标签会带有data-reactid属性,储存server render结果的校验值。
当在browser中React.render时会检查校验值是否一致,保证node以及browser环境下render的结果一致。因此开发过程中一定要保证render的结果保持一致,如果需要在browser中插入dom节点,可以使用insert等操作。禁止state以及props在两个环境下值不同。
如果通过校验,则React不会重新生成dom,只将事件监听器挂载在对应的节点下。

应用架构

采用flux的思想来组织应用,具体的方案我推荐facebook的flux或者reflux,这也是现在Github中获星最多的flux实现方案。两者的主要区别是reflux不通过Dispatcher来控制action的分发,reflux中使用了较多的magic来使得代码更加简洁高效。

如果项目的复杂程度不高(没有多个互相关联的store),我推荐使用Reflux,一般情况下其实一个store就够了,而且避免了处理store之间的通信问题。

╔═════════╗       ╔════════╗       ╔═════════════════╗
║ Actions ║──────>║ Stores ║──────>║ View Components ║
╚═════════╝       ╚════════╝       ╚═════════════════╝
     ^                                      │
     └──────────────────────────────────────┘

若项目较为庞大,考虑到代码的可控性、直观,以及更好地去控制各store之间的响应逻辑,使用flux更合适。

优点

采用flux来构建应用有以下优势:

  1. 将state在store中统一进行管理,实现业务与组建的分离,代码结构更加清晰。
  2. 由于action在store中进行监听,因此事件不需要再一层层通过props来进行传递,简化代码,而且也更容易将应用拆分成更细粒度的模块。
  3. 尽量使用props的情况下,代码可预测性很强。

组件开发

  1. react认为组件就是一个状态集,尽可能使得组件只拥有props。
  2. 当组件需要有自己的处理逻辑时需要用到state,比如控制input的value,弹出层自动隐藏、显示的逻辑等等。
  3. state并不会随着porps的更新而改变,因此在使用 state 时一定要注意是否有 componentWillReceiveProps。
  4. 业务代码为了方便以及速度可以不写 PropTypes,但是可复用的组件使用 PropTypes 来保证组件的正常运行是必要的,组件中的工具方法可以抽取出来写测试用例。

setState

state为key-value的集合,一般来说value都是基本类型,当state的数据结构层次很深的时候,操作state就会变成很头疼的事情。

深拷贝

// shallow copy
var state = deepCopy(this.state);
state.valueWantChange = vale;
this.setState(state);

深拷贝方法没有问题,但由于deepCopy效率很低,一般都不推荐使用。

forceUpdate

this.state.valueWantChange = vale;
this.forceUpdate(); // this.setState(this.state);

在以下两种情况会用到 forceUpdate

  • 手动更改了 state 之后需要触发 render
  • 做了除更改props和state之外的操作后,需要render。

但是使用forceUpdate 会跳过 shouldComponentUpdate 的过程,会触发子组件的所有lifeCycle方法(包括shouldComponentUpdate)从而造成性能的浪费。因此为了组件更加清晰高效,应该避免使用forceUpdate。

Immutability Helpers

我推荐使用React.addons来管理state
You can alleviate this by only copying objects that need to be changed and by reusing the objects that haven't changed.

import react from 'react/addons'
var newData = React.addons.update(myData, {
  x: {y: {z: {$set: 7}}},
  a: {b: {$push: [9]}}
});
this.setState(newData);

下面是update的基本语法。如果用过mongo应该对此十分熟悉。

  • {$push: array} push() all the items in array on the target.
  • {$unshift: array} unshift() all the items in array on the target.
  • {$splice: array of arrays} for each item in arrays call splice() on the target with the parameters provided by the item.
  • {$set: any} replace the target entirely.
  • {$merge: object} merge the keys of object with the target.
  • {$apply: function} passes in the current value to the function and updates it with the new returned value.

YeatsZhang
720 声望26 粉丝

frontend developer